#include "UIMusicList.h"
#include "UI.h"
#include "SceneMusicSelect.h"
#include <fstream>

//========================================
//
//Music List
//
//========================================
MusicList::MusicList() :EventHelper(this)
{
	itemTitleStyle = TTFConfig(FONTB, 32);
	itemArtistStyle = TTFConfig(FONTB, 18);
	acthover = TintTo::create(0.2f, pUI->themeColor3B());
	actselect = TintTo::create(0.2f, pUI->themeColor3B());
}

MusicList * MusicList::create(Vec2 listpos, Size listarea, float itemheight, MusicListManager* plistmgr, MusicLevelListManager* plevelmgr)
{
	auto mlst = new MusicList();
	mlst->initWithColor(THEMECOLORBA(0));
	mlst->setContentSize(Size(listarea.width, 0));
	mlst->listmgr = plistmgr;
	mlst->levelmgr = plevelmgr;
	mlst->listArea = listarea;
	mlst->listPosition = listpos;
	mlst->itemheight = itemheight;
	mlst->setName("MusicList");
	mlst->createList();
	UI::setNodeAnch(mlst, ANCH_BL);

	return mlst;
}

void MusicList::createList()
{
	auto listdata = &(listmgr->listdata);
	for (vector<MusicListManager::MUSICSETINFO>::iterator iter = --listdata->end(); iter != listdata->begin(); iter--)
	{
		addItem(iter->id, iter->title, iter->artist, iter->coverPath);
	}
	if (listdata->size() > 0)
		addItem(
			listdata->begin()->id,
			listdata->begin()->title,
			listdata->begin()->artist,
			listdata->begin()->coverPath
		);
}

void MusicList::addItem(string setid, string title, string artist, string coverpath)
{
	auto item = MusicListItem::create(setid, title, artist, coverpath, this);
	auto index = getChildrenCount();
	auto posy = (itemheight + itempadding)*index;
	item->setPositionY(posy);
	item->setTag(index);
	changeHeight((itemheight + itempadding)*(index + 1));
	addChild(item);
}

MusicListItem * MusicList::getItemByIndex(int index)
{
	return (MusicListItem*)getChildByTag(index);
}

void MusicList::openLevelList()
{
	//isLevelListAnime = true;
	auto levelitemheight = itemheight / 2;
	levelmgr->loadList(selectedItem->setid);
	auto itemcount = levelmgr->listdata.size();
	changeHeight(getContentSize().height - openedLevelListHeight);
	if (openedLevelListIndex >= 0)
	{
		for (UINT i = openedLevelListIndex; i < listmgr->listdata.size(); i++)
		{
			getItemByIndex(i)->runAction(EaseBackOut::create(MoveBy::create(.25f, Vec2(0, -openedLevelListHeight))));
		}
	}
	openedLevelListHeight = itemcount*levelitemheight;
	changeHeight(getContentSize().height + openedLevelListHeight);
	for (UINT i = selectedindex; i < listmgr->listdata.size(); i++)
	{
		getItemByIndex(i)->runAction(EaseBackOut::create(MoveBy::create(.25f, Vec2(0, openedLevelListHeight))));
	}
	auto listpos = (frameSize.height / 2) - (selectedindex*(itemheight + itempadding) + openedLevelListHeight / 2);
	if (listpos > 0) listpos = 0;
	else if (listpos < listArea.height - getContentSize().height) listpos = listArea.height - getContentSize().height;
	runAction(EaseBackOut::create(MoveTo::create(.25f, Vec2(0, listpos))));
	openedLevelListIndex = selectedindex;

	auto closingcount = levelItems.size();
	auto closingdelay = .1f / closingcount;
	for (auto iter : levelItems)
	{
		closingcount--;
		iter->runAction(
			Sequence::create(
				FadeOut::create(closingdelay*closingcount),
				RemoveSelf::create(),
				NULL
			)
		);
	}
	levelItems.clear();
	selectedLevelIndex = -1;
	auto newcount = 0;
	auto newdelay = .15f / levelmgr->listdata.size();
	auto levelItemPos = selectedindex*(itemheight + itempadding) + openedLevelListHeight;
	for (auto leveldata : levelmgr->listdata)
	{
		newcount++;
		auto newitem = MusicLevelListItem::create(
			leveldata.id,
			leveldata.maptype == "1" ? leveldata.keys + "K" :
			leveldata.keys == "8" ? "SP" : "DP",
			leveldata.level,
			leveldata.difficult,
			Size(listArea.width, levelitemheight)
		);
		//newitem->setOpacity(0);
		//newitem->setPosition(-listArea.width, levelItemPos - levelitemheight*newcount);
		newitem->setPosition(0, levelItemPos - levelitemheight*newcount);
		newitem->setSkewX(90);
		addChild(newitem);
		levelItems.push_back(newitem);
		//newitem->runAction(Sequence::create(DelayTime::create(newdelay*newcount), MoveBy::create(.15f, Vec2(listArea.width, 0)), NULL));
		newitem->runAction(
			Sequence::create(
				DelayTime::create(newdelay*newcount),
				SkewTo::create(.2f, 0, 0),
				NULL)
		);
		newitem->setAdditionalEventAction(MOUSEUP, CC_CALLBACK_0(MusicList::changeSelectedLevel, this));
		if (atoi(newitem->id.c_str()) == pNotemgr->mapId)
		{
			newitem->select();
			selectedLevelIndex = newcount - 1;
		}
	}
	if (selectedLevelIndex == -1)
	{
		levelItems[0]->select();
		selectedLevelIndex = 0;
	}
}

void MusicList::changeSelectedLevel()
{
	int index = 0;
	for (auto item : levelItems)
	{
		if (!item->isMouseHover())
		{
			item->disselect();
		}
		else
		{
			selectedLevelIndex = index;
		}
		index++;
	}
	runAdditionalEventAction(MOUSEUP);
}

bool MusicList::isHover(Event * e)
{
	return isMouseHoverArea(getParent()->convertToWorldSpace(Vec2::ZERO), listArea, e) && isMouseHoverNode(this, e, orbitAngelZ);
}

void MusicList::onMouseMove(Event * e)
{
	auto mouseloc = getMouseLoc(e);
	if (isHover(e))
	{
		Vec2 hoverpos;
		if (orbitAngelZ == 0)
		{
			hoverpos = getMouseLocInNode(this, e);
		}
		else
		{
			auto logicloc = UI::convertOrbitPos(mouseloc, 0, listArea.width, orbitAngelZ);
			hoverpos = convertToNodeSpace(logicloc);
		}
		int curhoverindex = 0;
		if (hoverpos.y < selectedindex*(itemheight + itempadding))
		{
			curhoverindex = (hoverpos.y + itempadding*0.5) / (itemheight + itempadding);
		}
		else if (hoverpos.y < selectedindex*(itemheight + itempadding) + openedLevelListHeight)
		{
			curhoverindex = selectedindex;
		}
		else
		{
			curhoverindex = (hoverpos.y - openedLevelListHeight + itempadding*0.5) / (itemheight + itempadding);
		}
		if ((UINT)curhoverindex < listmgr->listdata.size())
		{
			auto item = getItemByIndex(curhoverindex);
			item->hover();
			if (hoverindex == -1) hoverindex = curhoverindex;
			else if (hoverindex != curhoverindex)
			{
				if (hoverindex != selectedindex)
				{
					auto itemleave = getItemByIndex(hoverindex);
					itemleave->leave();
				}
				hoverindex = curhoverindex;
			}
		}
		if ((mouseloc != mousePosOnKeyDown) && isMouseKeyDown[MOUSELEFT])
		{
			isDragging = true;
		}
	}
	else
	{
		if (hoverindex != -1 && hoverindex != selectedindex)
		{
			auto itemleave = getItemByIndex(hoverindex);
			itemleave->leave();
			hoverindex = -1;
		}
	}
	if (isDragging) setPositionY(listPosYOnKeyDown + (mouseloc.y - mousePosOnKeyDown.y));
}

void MusicList::onMouseDown(Event * e)
{
	auto mouseloc = getMouseLoc(e);
	if (isHover(e))
	{
		if (mouseKey == MOUSELEFT)
		{
			mousePosOnKeyDown = mouseloc;
			listPosYOnKeyDown = getPositionY();
		}
	}
}

void MusicList::onMouseUp(Event * e)
{
	if (mouseKey == MOUSELEFT)
	{
		auto mouseloc = getMouseLoc(e);
		if (!isDragging && isHover(e) && selectedindex != hoverindex && getNumberOfRunningActions() == 0)
		{
			if (selectedindex >= 0)
			{
				selectedItem = getItemByIndex(selectedindex);
				selectedItem->disselect();
				selectedItem->leave();
			}
			auto hoveritem = getItemByIndex(hoverindex);
			hoveritem->selected();
			selectedindex = hoverindex;
			selectedItem = getItemByIndex(selectedindex);
			selectedSetChanged = true;
			openLevelList();
			runAdditionalEventAction(MOUSEUP);
		}
		else isDragging = false;
		auto scaledheight = pUI->getNodeScaledSize(this).height;
		if (scaledheight >= listArea.height)
		{
			if (getPositionY() + scaledheight < listArea.height)
				runAction(EaseBackOut::create(MoveTo::create(0.33f, Vec2(getPositionX(), listArea.height - scaledheight))));
			else if (getPositionY() > 0)
				runAction(EaseBackOut::create(MoveTo::create(0.33f, Vec2(getPositionX(), 0))));
		}
		else
		{
			runAction(EaseBackOut::create(MoveTo::create(0.33f, Vec2(getPositionX(), (listArea.height - scaledheight)*0.5))));
		}
	}
}

//========================================
//
//Music List Item
//
//========================================
MusicListItem * MusicListItem::create(string setid, string title, string artist, string coverpath, MusicList* list)
{
	auto mli = new MusicListItem();
	mli->plist = list;
	mli->setid = setid;
	mli->title = title;
	mli->artist = artist;
	mli->coverpath = coverpath;
	mli->acthover = TintTo::create(0.2f, pUI->themeColor3B());
	mli->actselect = TintTo::create(0.2f, pUI->themeColor3B());
	mli->setOpacity(192);

	auto cliplayer = LayerGradient::create(THEMECOLORBA(255), THEMECOLORBA(128), Vec2(1, 0));
	cliplayer->changeWidthAndHeight(list->listArea.width, list->itemheight);
	mli->addChild(cliplayer);
	mli->setStencil(cliplayer);

	mli->labeltitle = Label::createWithTTF(list->itemTitleStyle, title);
	UI::setNodeAnch(mli->labeltitle, ANCH_BL);
	mli->labeltitle->setPosition(list->listArea.width*0.05, list->itemheight*0.42);
	mli->labeltitle->setTextColor(TEXTCOLORB);
	mli->addChild(mli->labeltitle);
	if (mli->labeltitle->getContentSize().width > list->listArea.width)
	{
		mli->labeltitle->runAction(
			RepeatForever::create(
				Sequence::create(
					EaseSineInOut::create(MoveTo::create(5.f, Vec2(-(mli->labeltitle->getContentSize().width - list->listArea.width*0.95), mli->labeltitle->getPositionY()))),
					DelayTime::create(.5),
					EaseSineInOut::create(MoveTo::create(5.f, Vec2(list->listArea.width*0.05, mli->labeltitle->getPositionY()))),
					DelayTime::create(.5),
					NULL
				)
			)
		);
	}

	mli->labelartist = Label::createWithTTF(list->itemArtistStyle, artist);
	UI::setNodeAnch(mli->labelartist, ANCH_TL);
	mli->labelartist->setPosition(list->listArea.width*0.08, list->itemheight*0.41);
	mli->labelartist->setTextColor(TEXTCOLORB);
	mli->addChild(mli->labelartist);
	if (mli->labelartist->getContentSize().width > list->listArea.width)
	{
		mli->labelartist->runAction(
			RepeatForever::create(
				Sequence::create(
					EaseSineInOut::create(MoveTo::create(3.f, Vec2(mli->labelartist->getContentSize().width - list->listArea.width*0.92, mli->labelartist->getPositionY()))),
					DelayTime::create(1.),
					EaseSineInOut::create(MoveTo::create(3.f, Vec2(list->listArea.width*0.05, mli->labelartist->getPositionY()))),
					DelayTime::create(1.),
					NULL
				)
			)
		);
	}

	mli->border = LayerColor::create(TEXTCOLORB, 10, list->itemheight);
	mli->addChild(mli->border);

	mli->setName(setid);

	return mli;
}

void MusicListItem::hover()
{
	if (!onhover)
	{
		onhover = true;
		border->runAction(ScaleTo::create(.1f, 3, 1));
	}
}

void MusicListItem::leave()
{
	if (onhover)
	{
		onhover = false;
		border->runAction(ScaleTo::create(.1f, 1, 1));
	}
}

void MusicListItem::selected()
{
	float actdura = 0.05f;
	border->runAction(
		RepeatForever::create(
			Sequence::create(
				FadeTo::create(actdura, 128),
				FadeTo::create(actdura, 255),
				NULL
			)
		)
	);
}

void MusicListItem::disselect()
{
	border->stopAllActions();
	border->runAction(FadeTo::create(0, 255));
}

//========================================
//
//Music Level Item List
//
//========================================

MusicLevelListItem * MusicLevelListItem::create(string id, string keys, string level, string difficult, Size size)
{
	auto mlli = new MusicLevelListItem();
	//mlli->initWithColor(THEMECOLORBA(0));
	mlli->initWithColor(THEMECOLORBA(255), THEMECOLORBA(128), Vec2::UNIT_X);
	mlli->changeWidthAndHeight(size.width, size.height);

	mlli->id = id;
	mlli->keys = keys;
	mlli->level = level;
	mlli->diff = difficult;

	auto clip = ClippingRectangleNode::create(Rect(Vec2::ZERO, size));
	mlli->addChild(clip);

	auto vmidline = size.height / 2;
	auto font = TTFConfig(FONTA, 36);

	auto labelKeys = Label::createWithTTF(font, keys);
	UI::setNodeAnch(labelKeys, ANCH_ML);
	labelKeys->setPosition(size.width*.02f, vmidline);
	labelKeys->setTextColor(TEXTCOLORB);
	clip->addChild(labelKeys);

	auto labellevel = Label::createWithTTF(font, level);
	UI::setNodeAnch(labellevel, ANCH_MR);
	labellevel->setPosition(size.width*.98f, vmidline);
	labellevel->setTextColor(TEXTCOLORB);
	clip->addChild(labellevel);

	font.fontSize = 20;
	font.fontFilePath = FONTB;
	auto labeldiff = Label::createWithTTF(font, difficult);
	UI::setNodeAnch(labeldiff, ANCH_M);
	labeldiff->setPosition(size.width*.5f, vmidline);
	labeldiff->setTextColor(TEXTCOLORB);
	clip->addChild(labeldiff);

	auto ptrwidth = sqrt(size.height*size.height*.5f);

	for (int i = 0; i < 4; i++)
	{
		auto ptr = LayerColor::create(TEXTCOLORBA(0), ptrwidth, ptrwidth);
		UI::setNodeAnch(ptr, ANCH_M);
		ptr->setScale(1.f - i % 2 * .2f);
		if (i > 1)
		{
			ptr->setPosition(size.width*.2f, size.height*.5f);
			ptr->runAction(RepeatForever::create(RotateBy::create(.25f, -60 - i % 2 * 20)));
		}
		else
		{
			ptr->setPosition(size.width*.8f, size.height*.5f);
			ptr->runAction(RepeatForever::create(RotateBy::create(.25f, 60 + i % 2 * 20)));
		}
		clip->addChild(ptr);
		mlli->ptrs.push_back(ptr);
	}

	return mlli;
}

void MusicLevelListItem::select()
{
	auto act = RepeatForever::create(
		Sequence::create(
			FadeTo::create(.1f, 128),
			FadeTo::create(.1f, 64),
			NULL
		)
	);
	for (auto ptr : ptrs)
	{
		auto tmpact = act->clone();
		tmpact->setFlags(1);
		ptr->runAction(tmpact);
	}
}

void MusicLevelListItem::disselect()
{
	for (auto ptr : ptrs)
	{
		ptr->stopActionsByFlags(1);
		ptr->runAction(FadeTo::create(.05f, 0));
	}
}

bool MusicLevelListItem::isMouseHover()
{
	return mouseHover;
}

void MusicLevelListItem::onMouseMove(Event * e)
{
	if (mouseStatus == MOUSEENTER)
	{
		for (auto ptr : ptrs) ptr->runAction(FadeTo::create(.1f, 64));
		mouseHover = true;
	}
	else if (mouseStatus == MOUSELEAVE)
	{
		for (auto ptr : ptrs) ptr->runAction(FadeTo::create(.1f, 0));
		mouseHover = false;
	}
}

void MusicLevelListItem::onMouseDown(Event * e)
{
	if (mouseStatus == MOUSEENTER || mouseStatus == MOUSEHOVER)
		mouseDownPos = getMouseLoc(e);
}

void MusicLevelListItem::onMouseUp(Event * e)
{
	if ((mouseStatus == MOUSEENTER || mouseStatus == MOUSEHOVER) && mouseDownPos == getMouseLoc(e))
	{
		select();
		runAdditionalEventAction(MOUSEUP);
	}
}

